<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>Spring源码系列-第12章-SpringBoot源码-自动配置原理和内嵌Tomcat启动原理 | 风祈的时光录</title><meta name="keywords" content="Spring，框架，spring源码"><meta name="author" content="youthlql"><meta name="copyright" content="youthlql"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="SpringBoot源码-自动配置原理和内嵌Tomcat启动原理">
<meta property="og:type" content="article">
<meta property="og:title" content="Spring源码系列-第12章-SpringBoot源码-自动配置原理和内嵌Tomcat启动原理">
<meta property="og:url" content="https://imlql.cn/post/e3da4d66.html">
<meta property="og:site_name" content="风祈的时光录">
<meta property="og:description" content="SpringBoot源码-自动配置原理和内嵌Tomcat启动原理">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://npm.elemecdn.com/lql_static@latest/logo/spring.png">
<meta property="article:published_time" content="2023-01-05T16:01:02.000Z">
<meta property="article:modified_time" content="2023-01-05T15:24:36.505Z">
<meta property="article:author" content="youthlql">
<meta property="article:tag" content="Spring源码">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://npm.elemecdn.com/lql_static@latest/logo/spring.png"><link rel="shortcut icon" href="https://npm.elemecdn.com/youthlql@1.0.8/blog/favicon.png"><link rel="canonical" href="https://imlql.cn/post/e3da4d66"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//hm.baidu.com"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://npm.elemecdn.com/@fortawesome/fontawesome-free@6/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://npm.elemecdn.com/@fancyapps/ui/dist/fancybox.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?f693ff99cc7e613b88cf5b729a14b48b";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"search.xml","languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: {"defaultEncoding":2,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"簡"},
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery@2/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery@2/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: true,
  isAnchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'Spring源码系列-第12章-SpringBoot源码-自动配置原理和内嵌Tomcat启动原理',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2023-01-05 23:24:36'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><link rel="stylesheet" href="https://npm.elemecdn.com/lql_static@latest/butterfly_static/css/ali_icon.css"><link rel="stylesheet" href="https://npm.elemecdn.com/lql_static@latest/butterfly_static/css/2-24-mogai.css"><meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/atom.xml" title="风祈的时光录" type="application/atom+xml">
</head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/avatar/2.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data is-center"><div class="data-item"><a href="/archives/"><div class="headline">文章</div><div class="length-num">37</div></a></div><div class="data-item"><a href="/tags/"><div class="headline">标签</div><div class="length-num">21</div></a></div><div class="data-item"><a href="/categories/"><div class="headline">分类</div><div class="length-num">13</div></a></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw iconfont icon-shouyex"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw iconfont icon-zuixinwenzhang_huaban"></i><span> 找文章</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/categories/"><i class="fa-fw iconfont icon-fenlei1"></i><span> 分类</span></a></li><li><a class="site-page child" href="/tags/"><i class="fa-fw iconfont icon-biaoqian1"></i><span> 标签</span></a></li><li><a class="site-page child" href="/archives/"><i class="fa-fw iconfont icon-shijianzhou"></i><span> 归档</span></a></li></ul></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://npm.elemecdn.com/lql_static@latest/logo/spring.png')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">风祈的时光录</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw iconfont icon-shouyex"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw iconfont icon-zuixinwenzhang_huaban"></i><span> 找文章</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/categories/"><i class="fa-fw iconfont icon-fenlei1"></i><span> 分类</span></a></li><li><a class="site-page child" href="/tags/"><i class="fa-fw iconfont icon-biaoqian1"></i><span> 标签</span></a></li><li><a class="site-page child" href="/archives/"><i class="fa-fw iconfont icon-shijianzhou"></i><span> 归档</span></a></li></ul></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">Spring源码系列-第12章-SpringBoot源码-自动配置原理和内嵌Tomcat启动原理</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2023-01-05T16:01:02.000Z" title="发表于 2023-01-06 00:01:02">2023-01-06</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-01-05T15:24:36.505Z" title="更新于 2023-01-05 23:24:36">2023-01-05</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Spring/">Spring</a><i class="fas fa-angle-right post-meta-separator"></i><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Spring/%E6%BA%90%E7%A0%81V1/">源码V1</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">5.1k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>26分钟</span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="第12章-SpringBoot源码-自动配置原理和内嵌Tomcat启动原理"><a href="#第12章-SpringBoot源码-自动配置原理和内嵌Tomcat启动原理" class="headerlink" title="第12章-SpringBoot源码-自动配置原理和内嵌Tomcat启动原理"></a>第12章-SpringBoot源码-自动配置原理和内嵌Tomcat启动原理</h1><h2 id="嵌入式Tomcat与Spring整合"><a href="#嵌入式Tomcat与Spring整合" class="headerlink" title="嵌入式Tomcat与Spring整合"></a>嵌入式Tomcat与Spring整合</h2><h3 id="测试类"><a href="#测试类" class="headerlink" title="测试类"></a>测试类</h3><h4 id="测试项目目录"><a href="#测试项目目录" class="headerlink" title="测试项目目录"></a>测试项目目录</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">springboot-first</span><br><span class="line">├── common_usetree.txt</span><br><span class="line">├── pom.xml</span><br><span class="line">├── springboot-first.iml</span><br><span class="line">├── src/</span><br><span class="line">|  ├── main/</span><br><span class="line">|  |  ├── java/</span><br><span class="line">|  |  |  └── cn/</span><br><span class="line">|  |  |     └── imlql/</span><br><span class="line">|  |  |        └── boot/</span><br><span class="line">|  |  |           ├── config/</span><br><span class="line">|  |  |           |  ├── SpringConfig.java</span><br><span class="line">|  |  |           |  └── SpringMVCConfig.java</span><br><span class="line">|  |  |           ├── controller/</span><br><span class="line">|  |  |           |  └── HelloController.java</span><br><span class="line">|  |  |           ├── Main.java</span><br><span class="line">|  |  |           ├── QuickAppStarter.java</span><br><span class="line">|  |  └── resources/</span><br><span class="line">|  └── test/</span><br><span class="line">|     └── java/</span><br><span class="line">└── work/</span><br><span class="line">   └── Tomcat/</span><br><span class="line">      └── localhost/</span><br><span class="line">         └── boot/</span><br></pre></td></tr></table></figure>

<h4 id="pom-xml"><a href="#pom-xml" class="headerlink" title="pom.xml"></a>pom.xml</h4><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.example<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>springboot-first<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">maven.compiler.source</span>&gt;</span>8<span class="tag">&lt;/<span class="name">maven.compiler.source</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">maven.compiler.target</span>&gt;</span>8<span class="tag">&lt;/<span class="name">maven.compiler.target</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-webmvc<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.3.5<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">&lt;!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.tomcat.embed<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>tomcat-embed-core<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>8.5.64<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">&lt;!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.tomcat.embed<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>tomcat-embed-jasper<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>8.5.64<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="Main"><a href="#Main" class="headerlink" title="Main"></a>Main</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.imlql.boot;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.catalina.Context;</span><br><span class="line"><span class="keyword">import</span> org.apache.catalina.LifecycleException;</span><br><span class="line"><span class="keyword">import</span> org.apache.catalina.startup.Tomcat;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> LifecycleException </span>&#123;</span><br><span class="line">        <span class="comment">//自己写Tomcat的启动源码</span></span><br><span class="line">        Tomcat tomcat = <span class="keyword">new</span> Tomcat();</span><br><span class="line"></span><br><span class="line">        tomcat.setPort(<span class="number">8888</span>);</span><br><span class="line">        tomcat.setHostname(<span class="string">&quot;localhost&quot;</span>);</span><br><span class="line">        tomcat.setBaseDir(<span class="string">&quot;.&quot;</span>);</span><br><span class="line">        <span class="comment">// user.dir代表当前工作目录</span></span><br><span class="line">        Context context = tomcat.addWebapp(<span class="string">&quot;/boot&quot;</span>, System.getProperty(<span class="string">&quot;user.dir&quot;</span>) + <span class="string">&quot;/src/main&quot;</span>);</span><br><span class="line">        tomcat.start();<span class="comment">//启动tomcat 注解版MVC利用Tomcat SPI机制</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        tomcat.getServer().await(); <span class="comment">//服务器等待</span></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="QuickAppStarter"><a href="#QuickAppStarter" class="headerlink" title="QuickAppStarter"></a>QuickAppStarter</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.imlql.boot;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.imlql.boot.config.SpringConfig;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.imlql.boot.config.SpringMVCConfig;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletRegistration;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 最快速的整合注解版SpringMVC和Spring的</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">QuickAppStarter</span> <span class="keyword">extends</span> <span class="title">AbstractAnnotationConfigDispatcherServletInitializer</span> </span>&#123;</span><br><span class="line">   <span class="meta">@Override</span> <span class="comment">//根容器的配置（Spring的配置文件===Spring的配置类）</span></span><br><span class="line">   <span class="keyword">protected</span> Class&lt;?&gt;[] getRootConfigClasses() &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> Class&lt;?&gt;[]&#123;SpringConfig.class&#125;;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Override</span> <span class="comment">//web容器的配置（SpringMVC的配置文件===SpringMVC的配置类）</span></span><br><span class="line">   <span class="keyword">protected</span> Class&lt;?&gt;[] getServletConfigClasses() &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> Class&lt;?&gt;[]&#123;SpringMVCConfig.class&#125;;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Override</span> <span class="comment">//Servlet的映射，DispatcherServlet的映射路径</span></span><br><span class="line">   <span class="keyword">protected</span> String[] getServletMappings() &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> String[]&#123;<span class="string">&quot;/&quot;</span>&#125;;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">customizeRegistration</span><span class="params">(ServletRegistration.Dynamic registration)</span> </span>&#123;</span><br><span class="line"><span class="comment">//    super.customizeRegistration(registration);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//    registration.addMapping(&quot;&quot;);//</span></span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="SpringConfig"><a href="#SpringConfig" class="headerlink" title="SpringConfig"></a>SpringConfig</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@ComponentScan(value = &quot;cn.imlql.boot&quot;,excludeFilters = &#123;</span></span><br><span class="line"><span class="meta">      @ComponentScan.Filter(type= FilterType.ANNOTATION,value = Controller.class)</span></span><br><span class="line"><span class="meta">&#125;)</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringConfig</span> </span>&#123;</span><br><span class="line">   <span class="comment">//Spring的父容器</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="SpringMVCConfig"><a href="#SpringMVCConfig" class="headerlink" title="SpringMVCConfig"></a>SpringMVCConfig</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@ComponentScan(value = &quot;cn.imlql.boot&quot;,includeFilters = &#123;</span></span><br><span class="line"><span class="meta">      @ComponentScan.Filter(type= FilterType.ANNOTATION,value = Controller.class)</span></span><br><span class="line"><span class="meta">&#125;,useDefaultFilters = false)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringMVCConfig</span> </span>&#123;</span><br><span class="line">   <span class="comment">//SpringMVC的子容器，能扫描的Spring容器中的组件</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="HelloController"><a href="#HelloController" class="headerlink" title="HelloController"></a>HelloController</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.imlql.boot.controller;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloController</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/hello66&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;66666666~~~~~&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="测试效果"><a href="#测试效果" class="headerlink" title="测试效果"></a>测试效果</h3><img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022185818042.png" >





<h2 id="再来简单捋一下SPI如何启动的Web容器"><a href="#再来简单捋一下SPI如何启动的Web容器" class="headerlink" title="再来简单捋一下SPI如何启动的Web容器"></a>再来简单捋一下SPI如何启动的Web容器</h2><ol>
<li>我们看到上面很神奇的效果，我们自己写代码做到了类似SpringBoot的效果，不需要配置本地tomcat，直接就把Web应用启动起来了。</li>
<li>这里只是简单的捋一下，详细过程在前面讲过</li>
</ol>
<h3 id="META-INF-services"><a href="#META-INF-services" class="headerlink" title="META-INF/services"></a>META-INF/services</h3><img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022190130930.png">









<h3 id="AbstractAnnotationConfigDispatcherServletInitializer继承树"><a href="#AbstractAnnotationConfigDispatcherServletInitializer继承树" class="headerlink" title="AbstractAnnotationConfigDispatcherServletInitializer继承树"></a>AbstractAnnotationConfigDispatcherServletInitializer继承树</h3><p>我们的QuickAppStarter实现了</p>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022190304974.png"/>





<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022190418464.png"/>



<h3 id="SpringServletContainerInitializer"><a href="#SpringServletContainerInitializer" class="headerlink" title="SpringServletContainerInitializer"></a>SpringServletContainerInitializer</h3><p>利用Java的SPI加载META-INF/services下的实现类</p>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022190641317.png"/>



<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta">@HandlesTypes(WebApplicationInitializer.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringServletContainerInitializer</span> <span class="keyword">implements</span> <span class="title">ServletContainerInitializer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * Delegate the &#123;<span class="doctag">@code</span> ServletContext&#125; to any &#123;<span class="doctag">@link</span> WebApplicationInitializer&#125;</span></span><br><span class="line"><span class="comment">    * implementations present on the application classpath.</span></span><br><span class="line"><span class="comment">    * &lt;p&gt;Because this class declares @&#123;<span class="doctag">@code</span> HandlesTypes(WebApplicationInitializer.class)&#125;,</span></span><br><span class="line"><span class="comment">    * Servlet 3.0+ containers will automatically scan the classpath for implementations</span></span><br><span class="line"><span class="comment">    * of Spring&#x27;s &#123;<span class="doctag">@code</span> WebApplicationInitializer&#125; interface and provide the set of all</span></span><br><span class="line"><span class="comment">    * such types to the &#123;<span class="doctag">@code</span> webAppInitializerClasses&#125; parameter of this method.</span></span><br><span class="line"><span class="comment">    * &lt;p&gt;If no &#123;<span class="doctag">@code</span> WebApplicationInitializer&#125; implementations are found on the classpath,</span></span><br><span class="line"><span class="comment">    * this method is effectively a no-op. An INFO-level log message will be issued notifying</span></span><br><span class="line"><span class="comment">    * the user that the &#123;<span class="doctag">@code</span> ServletContainerInitializer&#125; has indeed been invoked but that</span></span><br><span class="line"><span class="comment">    * no &#123;<span class="doctag">@code</span> WebApplicationInitializer&#125; implementations were found.</span></span><br><span class="line"><span class="comment">    * &lt;p&gt;Assuming that one or more &#123;<span class="doctag">@code</span> WebApplicationInitializer&#125; types are detected,</span></span><br><span class="line"><span class="comment">    * they will be instantiated (and &lt;em&gt;sorted&lt;/em&gt; if the @&#123;<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment">    * org.springframework.core.annotation.Order <span class="doctag">@Order</span>&#125; annotation is present or</span></span><br><span class="line"><span class="comment">    * the &#123;<span class="doctag">@link</span> org.springframework.core.Ordered Ordered&#125; interface has been</span></span><br><span class="line"><span class="comment">    * implemented). Then the &#123;<span class="doctag">@link</span> WebApplicationInitializer#onStartup(ServletContext)&#125;</span></span><br><span class="line"><span class="comment">    * method will be invoked on each instance, delegating the &#123;<span class="doctag">@code</span> ServletContext&#125; such</span></span><br><span class="line"><span class="comment">    * that each instance may register and configure servlets such as Spring&#x27;s</span></span><br><span class="line"><span class="comment">    * &#123;<span class="doctag">@code</span> DispatcherServlet&#125;, listeners such as Spring&#x27;s &#123;<span class="doctag">@code</span> ContextLoaderListener&#125;,</span></span><br><span class="line"><span class="comment">    * or any other Servlet API componentry such as filters.</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@param</span> webAppInitializerClasses all implementations of</span></span><br><span class="line"><span class="comment">    * &#123;<span class="doctag">@link</span> WebApplicationInitializer&#125; found on the application classpath</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@param</span> servletContext the servlet context to be initialized</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@see</span> WebApplicationInitializer#onStartup(ServletContext)</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@see</span> AnnotationAwareOrderComparator</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">  	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onStartup</span><span class="params">(<span class="meta">@Nullable</span> Set&lt;Class&lt;?&gt;&gt; webAppInitializerClasses, ServletContext servletContext)</span></span></span><br><span class="line"><span class="function">			<span class="keyword">throws</span> ServletException </span>&#123;</span><br><span class="line"></span><br><span class="line">		List&lt;WebApplicationInitializer&gt; initializers = Collections.emptyList();</span><br><span class="line"></span><br><span class="line">		<span class="keyword">if</span> (webAppInitializerClasses != <span class="keyword">null</span>) &#123;</span><br><span class="line">			initializers = <span class="keyword">new</span> ArrayList&lt;&gt;(webAppInitializerClasses.size());</span><br><span class="line">			<span class="keyword">for</span> (Class&lt;?&gt; waiClass : webAppInitializerClasses) &#123;</span><br><span class="line">				<span class="comment">// Be defensive: Some servlet containers provide us with invalid classes,</span></span><br><span class="line">				<span class="comment">// no matter what @HandlesTypes says... 所有的非接口非抽象的WebApplicationInitializer实现类</span></span><br><span class="line">				<span class="keyword">if</span> (!waiClass.isInterface() &amp;&amp; !Modifier.isAbstract(waiClass.getModifiers()) &amp;&amp;</span><br><span class="line">						WebApplicationInitializer.class.isAssignableFrom(waiClass)) &#123;</span><br><span class="line">					<span class="keyword">try</span> &#123;</span><br><span class="line">						initializers.add((WebApplicationInitializer) <span class="comment">//集合负责保存满足上面条件的类</span></span><br><span class="line">								ReflectionUtils.accessibleConstructor(waiClass).newInstance());</span><br><span class="line">					&#125;</span><br><span class="line">					<span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">						<span class="keyword">throw</span> <span class="keyword">new</span> ServletException(<span class="string">&quot;Failed to instantiate WebApplicationInitializer class&quot;</span>, ex);</span><br><span class="line">					&#125;</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		<span class="keyword">if</span> (initializers.isEmpty()) &#123;</span><br><span class="line">			servletContext.log(<span class="string">&quot;No Spring WebApplicationInitializer types detected on classpath&quot;</span>);</span><br><span class="line">			<span class="keyword">return</span>;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">//下面会遍历所有满足要求的WebApplicationInitializer，调用他们的onStartup</span></span><br><span class="line">		servletContext.log(initializers.size() + <span class="string">&quot; Spring WebApplicationInitializers detected on classpath&quot;</span>);</span><br><span class="line">		AnnotationAwareOrderComparator.sort(initializers);</span><br><span class="line">		<span class="keyword">for</span> (WebApplicationInitializer initializer : initializers) &#123;</span><br><span class="line">			initializer.onStartup(servletContext); <span class="comment">//所有的 WebApplicationInitializer 的 onStartup</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="HandlesTypes"><a href="#HandlesTypes" class="headerlink" title="@HandlesTypes"></a>@HandlesTypes</h3><ol>
<li>其中@HandlesTypes注解表示可以处理的类，在<code>onStartup</code> 方法中，可以通过<code>Set&lt;Class&lt;?&gt;&gt; webAppInitializerClasses</code> 获取得到。</li>
<li>@HandlesTypes属于sun公司对Servlet定义的规范，包括tomcat,jetty等服务器都对它有不同的实现</li>
<li>tomcat的具体实现咱们这里不深究，可以肯定的是一定用到了Java的SPI，如下。</li>
</ol>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">ServiceLoader&lt;DataSaveService&gt; load = ServiceLoader.load(WebApplicationInitializer.class);</span><br></pre></td></tr></table></figure>

<ol start="4">
<li>tomcat具体对于@HandlesTypes一定是和上面类似甚至是一样的代码来加载WebApplicationInitializer的实现</li>
</ol>
<p>因为咱们的QuickAppStarter继承的AbstractAnnotationConfigDispatcherServletInitializer也属于WebApplicationInitializer，所以它就会被加载</p>
<h3 id="Servlet相关规范"><a href="#Servlet相关规范" class="headerlink" title="Servlet相关规范"></a>Servlet相关规范</h3><ol>
<li><p>tomcat会遵循sun公司的规范给每一个Servlet创建对象</p>
</li>
<li><p>所以DispatcherServlet肯定也会创建对象</p>
</li>
<li><p>Servlet的规范</p>
<ol>
<li>Servlet创建对象</li>
<li>Servlet调用Init初始化</li>
<li>每次请求调用service处理</li>
<li>tomcat停止的时候调用destroy进行销毁</li>
</ol>
</li>
<li><p>Serlvet是被谁调用开始初始化的属于tomcat的源码，我们这里不研究</p>
</li>
</ol>
<h3 id="DispatcherServlet"><a href="#DispatcherServlet" class="headerlink" title="DispatcherServlet"></a>DispatcherServlet</h3><ol>
<li>spring-web中有一个叫DispatcherServlet的类，很明显他是一个Servlet，所以tomcat启动的时候就会加载它，加载它的话当然是从父类一层一层加载的</li>
</ol>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211013195948793.png">

<ol start="2">
<li>也就是说是从Servlet最顶层开始一层一层往下面调用</li>
<li>最终我们发现FrameworkServlet里有一个核心方法</li>
</ol>
<h3 id="FrameworkServlet"><a href="#FrameworkServlet" class="headerlink" title="FrameworkServlet"></a>FrameworkServlet</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/** 追踪看web应用启动做了什么。</span></span><br><span class="line"><span class="comment"> * Overridden method of &#123;<span class="doctag">@link</span> HttpServletBean&#125;, invoked after any bean properties</span></span><br><span class="line"><span class="comment"> * have been set. Creates this servlet&#x27;s WebApplicationContext.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">initServletBean</span><span class="params">()</span> <span class="keyword">throws</span> ServletException </span>&#123;</span><br><span class="line">   getServletContext().log(<span class="string">&quot;Initializing Spring &quot;</span> + getClass().getSimpleName() + <span class="string">&quot; &#x27;&quot;</span> + getServletName() + <span class="string">&quot;&#x27;&quot;</span>);</span><br><span class="line">   <span class="keyword">if</span> (logger.isInfoEnabled()) &#123;</span><br><span class="line">      logger.info(<span class="string">&quot;Initializing Servlet &#x27;&quot;</span> + getServletName() + <span class="string">&quot;&#x27;&quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">long</span> startTime = System.currentTimeMillis();</span><br><span class="line"></span><br><span class="line">   <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">this</span>.webApplicationContext = initWebApplicationContext(); <span class="comment">//初始化WebIOC容器，那我们想一下大概率是在这里启动的IOC容器</span></span><br><span class="line">      initFrameworkServlet(); <span class="comment">//这又是留给子类的</span></span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">catch</span> (ServletException | RuntimeException ex) &#123;</span><br><span class="line">      logger.error(<span class="string">&quot;Context initialization failed&quot;</span>, ex);</span><br><span class="line">      <span class="keyword">throw</span> ex;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">if</span> (logger.isDebugEnabled()) &#123;</span><br><span class="line">      String value = <span class="keyword">this</span>.enableLoggingRequestDetails ?</span><br><span class="line">            <span class="string">&quot;shown which may lead to unsafe logging of potentially sensitive data&quot;</span> :</span><br><span class="line">            <span class="string">&quot;masked to prevent unsafe logging of potentially sensitive data&quot;</span>;</span><br><span class="line">      logger.debug(<span class="string">&quot;enableLoggingRequestDetails=&#x27;&quot;</span> + <span class="keyword">this</span>.enableLoggingRequestDetails +</span><br><span class="line">            <span class="string">&quot;&#x27;: request parameters and headers will be &quot;</span> + value);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">if</span> (logger.isInfoEnabled()) &#123;</span><br><span class="line">      logger.info(<span class="string">&quot;Completed initialization in &quot;</span> + (System.currentTimeMillis() - startTime) + <span class="string">&quot; ms&quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<ol>
<li><p><code>this.webApplicationContext = initWebApplicationContext();</code>没错，看名字就知道是从这里开始启动Web容器的。</p>
</li>
<li><p>然后我们就自己搭建了一个MySpringBoot项目，我们这个项目和SpringBoot官方的区别就是官方帮我们封装了很多自动配置类，帮我们给容器中放了很多组件，使得我们感觉开发更方便了。</p>
</li>
</ol>
<h2 id="SpringBoot启动导入了很多自动配置类"><a href="#SpringBoot启动导入了很多自动配置类" class="headerlink" title="SpringBoot启动导入了很多自动配置类"></a>SpringBoot启动导入了很多自动配置类</h2><p>为什么 @SpringBootApplication +SpringApplication.run(SpringbootSourceApplication.class, args);能把Spring+SpringMVC+Tomcat+其他场景都整合进来</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringbootSourceApplication</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(SpringbootSourceApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="pom-xml-1"><a href="#pom-xml-1" class="headerlink" title="pom.xml"></a>pom.xml</h3><figure class="highlight"><table><tr><td class="code"><pre><span class="line">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span><br><span class="line">&lt;project xmlns=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> xmlns:xsi=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="line">         xsi:schemaLocation=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span><br><span class="line">    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;</span><br><span class="line">    &lt;parent&gt;</span><br><span class="line">        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">        &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;</span><br><span class="line">        &lt;version&gt;2.4.4&lt;/version&gt;</span><br><span class="line">        &lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;</span><br><span class="line">    &lt;/parent&gt;</span><br><span class="line">    &lt;groupId&gt;com.atuigu.boot&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;springboot-source&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;</span><br><span class="line">    &lt;name&gt;springboot-source&lt;/name&gt;</span><br><span class="line">    &lt;description&gt;Demo project for Spring Boot&lt;/description&gt;</span><br><span class="line">    &lt;properties&gt;</span><br><span class="line">        &lt;java.version&gt;1.8&lt;/java.version&gt;</span><br><span class="line">    &lt;/properties&gt;</span><br><span class="line">    &lt;dependencies&gt;</span><br><span class="line">        &lt;dependency&gt;</span><br><span class="line">            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">            &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;</span><br><span class="line">        &lt;/dependency&gt;</span><br><span class="line"></span><br><span class="line">        &lt;dependency&gt;</span><br><span class="line">            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">            &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;</span><br><span class="line">            &lt;scope&gt;test&lt;/scope&gt;</span><br><span class="line">        &lt;/dependency&gt;</span><br><span class="line">    &lt;/dependencies&gt;</span><br><span class="line"></span><br><span class="line">    &lt;build&gt;</span><br><span class="line">        &lt;plugins&gt;</span><br><span class="line">            &lt;plugin&gt;</span><br><span class="line">                &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">                &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;</span><br><span class="line">            &lt;/plugin&gt;</span><br><span class="line">        &lt;/plugins&gt;</span><br><span class="line">    &lt;/build&gt;</span><br><span class="line"></span><br><span class="line">&lt;/project&gt;</span><br></pre></td></tr></table></figure>

<ol>
<li>首先是在Maven依赖上的支持，spring-boot-starter-xxx的这种依赖内部又导入了很多的依赖，包括上面说的嵌入式tomcat，以及Spring，SpringMVC</li>
</ol>
<h3 id="SpringBootApplication原理"><a href="#SpringBootApplication原理" class="headerlink" title="@SpringBootApplication原理"></a>@SpringBootApplication原理</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Target(ElementType.TYPE)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Inherited</span></span><br><span class="line"><span class="meta">@SpringBootConfiguration</span></span><br><span class="line"><span class="meta">@EnableAutoConfiguration</span></span><br><span class="line"><span class="meta">@ComponentScan(excludeFilters = &#123; @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),</span></span><br><span class="line"><span class="meta">      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) &#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> SpringBootApplication &#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//......</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="SpringBootConfiguration"><a href="#SpringBootConfiguration" class="headerlink" title="@SpringBootConfiguration"></a>@SpringBootConfiguration</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Target(ElementType.TYPE)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> SpringBootConfiguration &#123;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@AliasFor(annotation = Configuration.class)</span></span><br><span class="line">   <span class="function"><span class="keyword">boolean</span> <span class="title">proxyBeanMethods</span><span class="params">()</span> <span class="keyword">default</span> <span class="keyword">true</span></span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这个注解的功能就相当于@Configuration</p>
<h3 id="EnableAutoConfiguration"><a href="#EnableAutoConfiguration" class="headerlink" title="@EnableAutoConfiguration"></a>@EnableAutoConfiguration</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Target(ElementType.TYPE)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Inherited</span></span><br><span class="line"><span class="meta">@AutoConfigurationPackage</span></span><br><span class="line"><span class="meta">@Import(AutoConfigurationImportSelector.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> EnableAutoConfiguration &#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//......</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="AutoConfigurationPackage"><a href="#AutoConfigurationPackage" class="headerlink" title="@AutoConfigurationPackage"></a>@AutoConfigurationPackage</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Target(ElementType.TYPE)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Inherited</span></span><br><span class="line"><span class="meta">@Import(AutoConfigurationPackages.Registrar.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> AutoConfigurationPackage &#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//......</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="AutoConfigurationPackage导入的AutoConfigurationPackages-Registrar类"><a href="#AutoConfigurationPackage导入的AutoConfigurationPackages-Registrar类" class="headerlink" title="@AutoConfigurationPackage导入的AutoConfigurationPackages.Registrar类"></a>@AutoConfigurationPackage导入的AutoConfigurationPackages.Registrar类</h2><h3 id="AutoConfigurationPackages-Registrar-registerBeanDefinitions"><a href="#AutoConfigurationPackages-Registrar-registerBeanDefinitions" class="headerlink" title="AutoConfigurationPackages.Registrar#registerBeanDefinitions()"></a>AutoConfigurationPackages.Registrar#registerBeanDefinitions()</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Registrar</span> <span class="keyword">implements</span> <span class="title">ImportBeanDefinitionRegistrar</span>, <span class="title">DeterminableImports</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerBeanDefinitions</span><span class="params">(AnnotationMetadata metadata, BeanDefinitionRegistry registry)</span> </span>&#123;</span><br><span class="line">      register(registry, <span class="keyword">new</span> PackageImports(metadata).getPackageNames().toArray(<span class="keyword">new</span> String[<span class="number">0</span>]));</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="function"><span class="keyword">public</span> Set&lt;Object&gt; <span class="title">determineImports</span><span class="params">(AnnotationMetadata metadata)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">return</span> Collections.singleton(<span class="keyword">new</span> PackageImports(metadata));</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022211609038.png" />

<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022211757069.png" />

<p>这里就是得到要注册哪些包下的信息，F7进入此方法。从这里你也能知道SpringBoot默认导的包是SpringbootXXXApplication所在的那个包层级</p>
<h3 id="AutoConfigurationPackages-register"><a href="#AutoConfigurationPackages-register" class="headerlink" title="AutoConfigurationPackages#register()"></a>AutoConfigurationPackages#register()</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">   <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">register</span><span class="params">(BeanDefinitionRegistry registry, String... packageNames)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">if</span> (registry.containsBeanDefinition(BEAN)) &#123;</span><br><span class="line">         BasePackagesBeanDefinition beanDefinition = (BasePackagesBeanDefinition) registry.getBeanDefinition(BEAN);</span><br><span class="line">         beanDefinition.addBasePackages(packageNames);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">else</span> &#123;</span><br><span class="line">         registry.registerBeanDefinition(BEAN, <span class="keyword">new</span> BasePackagesBeanDefinition(packageNames));</span><br><span class="line">      &#125;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String BEAN = AutoConfigurationPackages.class.getName();</span><br></pre></td></tr></table></figure>

<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022212045090.png"  />

<h3 id="AutoConfigurationPackages-BasePackagesBeanDefinition"><a href="#AutoConfigurationPackages-BasePackagesBeanDefinition" class="headerlink" title="AutoConfigurationPackages.BasePackagesBeanDefinition"></a>AutoConfigurationPackages.BasePackagesBeanDefinition</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">BasePackagesBeanDefinition</span> <span class="keyword">extends</span> <span class="title">GenericBeanDefinition</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">final</span> Set&lt;String&gt; basePackages = <span class="keyword">new</span> LinkedHashSet&lt;&gt;();</span><br><span class="line"></span><br><span class="line">   BasePackagesBeanDefinition(String... basePackages) &#123;</span><br><span class="line">      setBeanClass(BasePackages.class);</span><br><span class="line">      setRole(BeanDefinition.ROLE_INFRASTRUCTURE);</span><br><span class="line">      addBasePackages(basePackages);<span class="comment">//就是要指定最终要扫哪些包</span></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="keyword">public</span> Supplier&lt;?&gt; getInstanceSupplier() &#123;</span><br><span class="line">      <span class="keyword">return</span> () -&gt; <span class="keyword">new</span> BasePackages(StringUtils.toStringArray(<span class="keyword">this</span>.basePackages));</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">addBasePackages</span><span class="params">(String[] additionalBasePackages)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.basePackages.addAll(Arrays.asList(additionalBasePackages));</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="BeanDefinitionMap里的数据"><a href="#BeanDefinitionMap里的数据" class="headerlink" title="BeanDefinitionMap里的数据"></a>BeanDefinitionMap里的数据</h3><img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022212703485.png"  />

<p>此时beanDefinitionMap已经有了AutoConfigurationPackages，当处理到这个Bean的时候，最终发现这是个包导入的组件，最终就会导入这个包里面的组件</p>
<h2 id="EnableAutoConfiguration注解导入的AutoConfigurationImportSelector类"><a href="#EnableAutoConfiguration注解导入的AutoConfigurationImportSelector类" class="headerlink" title="@EnableAutoConfiguration注解导入的AutoConfigurationImportSelector类"></a>@EnableAutoConfiguration注解导入的AutoConfigurationImportSelector类</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AutoConfigurationImportSelector</span> <span class="keyword">implements</span> <span class="title">DeferredImportSelector</span>, <span class="title">BeanClassLoaderAware</span>,</span></span><br><span class="line"><span class="class">      <span class="title">ResourceLoaderAware</span>, <span class="title">BeanFactoryAware</span>, <span class="title">EnvironmentAware</span>, <span class="title">Ordered</span> </span>&#123;</span><br><span class="line">	</span><br><span class="line">          <span class="comment">//......</span></span><br><span class="line">          </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ol>
<li>AutoConfigurationImportSelector是用@Import注解导进来的</li>
<li>AutoConfigurationImportSelector根据它的名字很明显它是一个ImportSelector的实现类，了解ImportSelector的都应该知道它是通过<code>selectImports()</code>方法来实现导入哪些组件的</li>
</ol>
<h3 id="AutoConfigurationImportSelector-AutoConfigurationGroup-process"><a href="#AutoConfigurationImportSelector-AutoConfigurationGroup-process" class="headerlink" title="AutoConfigurationImportSelector.AutoConfigurationGroup#process()"></a>AutoConfigurationImportSelector.AutoConfigurationGroup#process()</h3><img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022214332439.png" />

<p>F7进入此方法</p>
<h3 id="AutoConfigurationImportSelector-getAutoConfigurationEntry"><a href="#AutoConfigurationImportSelector-getAutoConfigurationEntry" class="headerlink" title="AutoConfigurationImportSelector#getAutoConfigurationEntry()"></a>AutoConfigurationImportSelector#getAutoConfigurationEntry()</h3><img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022214425824.png" />

<p>F7进入此方法</p>
<h3 id="AutoConfigurationImportSelector-getCandidateConfigurations"><a href="#AutoConfigurationImportSelector-getCandidateConfigurations" class="headerlink" title="AutoConfigurationImportSelector#getCandidateConfigurations()"></a>AutoConfigurationImportSelector#getCandidateConfigurations()</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">   <span class="function"><span class="keyword">protected</span> List&lt;String&gt; <span class="title">getCandidateConfigurations</span><span class="params">(AnnotationMetadata metadata, AnnotationAttributes attributes)</span> </span>&#123;</span><br><span class="line">      List&lt;String&gt; configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),</span><br><span class="line">            getBeanClassLoader());</span><br><span class="line">      Assert.notEmpty(configurations, <span class="string">&quot;No auto configuration classes found in META-INF/spring.factories. If you &quot;</span></span><br><span class="line">            + <span class="string">&quot;are using a custom packaging, make sure that file is correct.&quot;</span>);</span><br><span class="line">      <span class="keyword">return</span> configurations;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span> Class&lt;?&gt; getSpringFactoriesLoaderFactoryClass() &#123;</span><br><span class="line">	<span class="keyword">return</span> EnableAutoConfiguration.class;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="SpringFactoriesLoader-loadFactoryNames"><a href="#SpringFactoriesLoader-loadFactoryNames" class="headerlink" title="SpringFactoriesLoader#loadFactoryNames()"></a>SpringFactoriesLoader#loadFactoryNames()</h3><img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022214744474.png" />



<h3 id="SpringFactoriesLoader-loadSpringFactories-加载类路径下META-INF-spring-factories的资源"><a href="#SpringFactoriesLoader-loadSpringFactories-加载类路径下META-INF-spring-factories的资源" class="headerlink" title="SpringFactoriesLoader#loadSpringFactories()加载类路径下META-INF/spring.factories的资源"></a>SpringFactoriesLoader#loadSpringFactories()加载类路径下META-INF/spring.factories的资源</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String FACTORIES_RESOURCE_LOCATION = <span class="string">&quot;META-INF/spring.factories&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> Map&lt;String, List&lt;String&gt;&gt; loadSpringFactories(ClassLoader classLoader) &#123;</span><br><span class="line">      Map&lt;String, List&lt;String&gt;&gt; result = cache.get(classLoader);</span><br><span class="line">      <span class="keyword">if</span> (result != <span class="keyword">null</span>) &#123;</span><br><span class="line">         <span class="keyword">return</span> result;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      result = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">         <span class="comment">//加载类路径下META-INF/spring.factories的资源</span></span><br><span class="line">         Enumeration&lt;URL&gt; urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);</span><br><span class="line">         <span class="keyword">while</span> (urls.hasMoreElements()) &#123;</span><br><span class="line">            URL url = urls.nextElement();</span><br><span class="line">            UrlResource resource = <span class="keyword">new</span> UrlResource(url);</span><br><span class="line">            Properties properties = PropertiesLoaderUtils.loadProperties(resource);</span><br><span class="line">            <span class="keyword">for</span> (Map.Entry&lt;?, ?&gt; entry : properties.entrySet()) &#123;</span><br><span class="line">               String factoryTypeName = ((String) entry.getKey()).trim();</span><br><span class="line">               String[] factoryImplementationNames =</span><br><span class="line">                     StringUtils.commaDelimitedListToStringArray((String) entry.getValue());</span><br><span class="line">               <span class="keyword">for</span> (String factoryImplementationName : factoryImplementationNames) &#123;</span><br><span class="line">                  result.computeIfAbsent(factoryTypeName, key -&gt; <span class="keyword">new</span> ArrayList&lt;&gt;())</span><br><span class="line">                        .add(factoryImplementationName.trim());</span><br><span class="line">               &#125;</span><br><span class="line">            &#125;</span><br><span class="line">         &#125;</span><br><span class="line"></span><br><span class="line">         <span class="comment">// Replace all lists with unmodifiable lists containing unique elements</span></span><br><span class="line">         result.replaceAll((factoryType, implementations) -&gt; implementations.stream().distinct()</span><br><span class="line">               .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));</span><br><span class="line">         cache.put(classLoader, result);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">catch</span> (IOException ex) &#123;</span><br><span class="line">         <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;Unable to load factories from location [&quot;</span> +</span><br><span class="line">               FACTORIES_RESOURCE_LOCATION + <span class="string">&quot;]&quot;</span>, ex);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> result;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>

<p>然后咱们就要找类路径下META-INF/spring.factories，并且名字是<code>org.springframework.boot.autoconfigure.EnableAutoConfiguration</code>的资源，这有点类似于SPI机制</p>
<h3 id="spring-factories"><a href="#spring-factories" class="headerlink" title="spring.factories"></a>spring.factories</h3><ol>
<li>不止这个包下有spring.factories文件，可能很多第三方的starter都有，这个包下的这些类只是Spring能想到的常用的组件。</li>
</ol>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022215644854.png" />



<h3 id="返回到AutoConfigurationImportSelector-getAutoConfigurationEntry"><a href="#返回到AutoConfigurationImportSelector-getAutoConfigurationEntry" class="headerlink" title="返回到AutoConfigurationImportSelector#getAutoConfigurationEntry()"></a>返回到AutoConfigurationImportSelector#getAutoConfigurationEntry()</h3><ol>
<li>自此这130个组件会先被放到List里，但不一定全部导入</li>
</ol>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022220450954.png" />

<ol start="2">
<li>然后这里会有一个过滤<code>configurations = getConfigurationClassFilter().filter(configurations);</code></li>
</ol>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022220655328.png" />

<ol start="3">
<li>最终这里只会有23个组件被放到容器中，为什么这里要过滤？看下面的@ConditionalOnClass注解，当容器中有KafkaTemplate这个类时才会导入KafkaAutoConfiguration，而KafkaTemplate这个类只有导入了kafka相关jar包才会有。意思就是你只有在maven中导入了相关jar包，才会给你自动配置</li>
</ol>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022223803718.png"/>



<p>还有下面这个SpringMvc的，当你有DispatcherServlet这个类的时候，才会给你自动配置web相关的东西。而有DispatcherServlet类就代表你导入了web的相关依赖</p>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022224029198.png" />







<h2 id="容器刷新在onRefresh步骤会启动Tomcat"><a href="#容器刷新在onRefresh步骤会启动Tomcat" class="headerlink" title="容器刷新在onRefresh步骤会启动Tomcat"></a>容器刷新在onRefresh步骤会启动Tomcat</h2><ol>
<li>在刚开始的时候我们自己实现的简易SpringBoot是利用SPI机制启动的Web容器</li>
<li>其实我们还要一个方法就是自己创建一个DispatcherServlet注册到Tomcat里，然后Tomcat就会调用Servlet相关初始化，最终调用到FrameworkServlet类里调用的<code>this.webApplicationContext = initWebApplicationContext();</code>，<strong>进而启动Web容器。在SpringBoot里使用的就是这种方式启动Web容器</strong></li>
</ol>
<h3 id="DispatcherServletAutoConfiguration"><a href="#DispatcherServletAutoConfiguration" class="headerlink" title="DispatcherServletAutoConfiguration"></a>DispatcherServletAutoConfiguration</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> org.springframework.boot.autoconfigure.web.servlet;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)</span></span><br><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="meta">@ConditionalOnWebApplication(type = Type.SERVLET)</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(DispatcherServlet.class)</span></span><br><span class="line"><span class="comment">//这里就是DispatcherServlet在自动配置之前，先自动配置ServletWebServerFactoryAutoConfiguration</span></span><br><span class="line"><span class="meta">@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DispatcherServletAutoConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * The bean name for a DispatcherServlet that will be mapped to the root URL &quot;/&quot;.</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = <span class="string">&quot;dispatcherServlet&quot;</span>;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * The bean name for a ServletRegistrationBean for the DispatcherServlet &quot;/&quot;.</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = <span class="string">&quot;dispatcherServletRegistration&quot;</span>;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line">   <span class="meta">@Conditional(DefaultDispatcherServletCondition.class)</span></span><br><span class="line">   <span class="meta">@ConditionalOnClass(ServletRegistration.class)</span></span><br><span class="line">   <span class="meta">@EnableConfigurationProperties(WebMvcProperties.class)</span></span><br><span class="line">   <span class="keyword">protected</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DispatcherServletConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="meta">@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)</span></span><br><span class="line">      <span class="function"><span class="keyword">public</span> DispatcherServlet <span class="title">dispatcherServlet</span><span class="params">(WebMvcProperties webMvcProperties)</span> </span>&#123;</span><br><span class="line">         DispatcherServlet dispatcherServlet = <span class="keyword">new</span> DispatcherServlet();</span><br><span class="line">         dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());</span><br><span class="line">         dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());</span><br><span class="line">         dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());</span><br><span class="line">         dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());</span><br><span class="line">         dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());</span><br><span class="line">         <span class="keyword">return</span> dispatcherServlet;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="meta">@Bean</span></span><br><span class="line">      <span class="meta">@ConditionalOnBean(MultipartResolver.class)</span></span><br><span class="line">      <span class="meta">@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)</span></span><br><span class="line">      <span class="function"><span class="keyword">public</span> MultipartResolver <span class="title">multipartResolver</span><span class="params">(MultipartResolver resolver)</span> </span>&#123;</span><br><span class="line">         <span class="comment">// Detect if the user has created a MultipartResolver but named it incorrectly</span></span><br><span class="line">         <span class="keyword">return</span> resolver;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line">   <span class="meta">@Conditional(DispatcherServletRegistrationCondition.class)</span></span><br><span class="line">   <span class="meta">@ConditionalOnClass(ServletRegistration.class)</span></span><br><span class="line">   <span class="meta">@EnableConfigurationProperties(WebMvcProperties.class)</span></span><br><span class="line">   <span class="meta">@Import(DispatcherServletConfiguration.class)</span></span><br><span class="line">   <span class="keyword">protected</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DispatcherServletRegistrationConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="meta">@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)</span></span><br><span class="line">      <span class="meta">@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)</span></span><br><span class="line">      <span class="function"><span class="keyword">public</span> DispatcherServletRegistrationBean <span class="title">dispatcherServletRegistration</span><span class="params">(DispatcherServlet dispatcherServlet,</span></span></span><br><span class="line"><span class="function"><span class="params">            WebMvcProperties webMvcProperties, ObjectProvider&lt;MultipartConfigElement&gt; multipartConfig)</span> </span>&#123;</span><br><span class="line">         DispatcherServletRegistrationBean registration = <span class="keyword">new</span> DispatcherServletRegistrationBean(dispatcherServlet,</span><br><span class="line">               webMvcProperties.getServlet().getPath());</span><br><span class="line">         registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);</span><br><span class="line">         registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());</span><br><span class="line">         multipartConfig.ifAvailable(registration::setMultipartConfig);</span><br><span class="line">         <span class="keyword">return</span> registration;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Order(Ordered.LOWEST_PRECEDENCE - 10)</span></span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DefaultDispatcherServletCondition</span> <span class="keyword">extends</span> <span class="title">SpringBootCondition</span> </span>&#123;</span><br><span class="line">		<span class="comment">// ......</span></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Order(Ordered.LOWEST_PRECEDENCE - 10)</span></span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DispatcherServletRegistrationCondition</span> <span class="keyword">extends</span> <span class="title">SpringBootCondition</span> </span>&#123;</span><br><span class="line">		<span class="comment">// ......</span></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ol>
<li><code>@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)</code></li>
<li>这里就是最关键的，@AutoConfigureAfter注解看名字就能大概明白是什么意思，这里就是DispatcherServlet在自动配置之前，先自动配置ServletWebServerFactoryAutoConfiguration</li>
</ol>
<h3 id="ServletWebServerFactoryAutoConfiguration"><a href="#ServletWebServerFactoryAutoConfiguration" class="headerlink" title="ServletWebServerFactoryAutoConfiguration"></a>ServletWebServerFactoryAutoConfiguration</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="meta">@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(ServletRequest.class)</span></span><br><span class="line"><span class="meta">@ConditionalOnWebApplication(type = Type.SERVLET)</span></span><br><span class="line"><span class="meta">@EnableConfigurationProperties(ServerProperties.class)</span></span><br><span class="line"><span class="meta">@Import(&#123; ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, //这里是最核心的</span></span><br><span class="line"><span class="meta">      ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, //这里都是嵌入式服务器</span></span><br><span class="line"><span class="meta">      ServletWebServerFactoryConfiguration.EmbeddedJetty.class, //这里都是嵌入式服务器</span></span><br><span class="line"><span class="meta">      ServletWebServerFactoryConfiguration.EmbeddedUndertow.class &#125;)</span> <span class="comment">//这里都是嵌入式服务器</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ServletWebServerFactoryAutoConfiguration</span> </span>&#123;</span><br><span class="line">	<span class="comment">// ......</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h3 id="ServletWebServerFactoryAutoConfiguration-BeanPostProcessorsRegistrar"><a href="#ServletWebServerFactoryAutoConfiguration-BeanPostProcessorsRegistrar" class="headerlink" title="ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar"></a>ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerBeanDefinitions</span><span class="params">(AnnotationMetadata importingClassMetadata,</span></span></span><br><span class="line"><span class="function"><span class="params">      BeanDefinitionRegistry registry)</span> </span>&#123;</span><br><span class="line">   <span class="keyword">if</span> (<span class="keyword">this</span>.beanFactory == <span class="keyword">null</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">//给容器中注册一个服务器的后置处理器</span></span><br><span class="line">   registerSyntheticBeanIfMissing(registry, <span class="string">&quot;webServerFactoryCustomizerBeanPostProcessor&quot;</span>,</span><br><span class="line">         WebServerFactoryCustomizerBeanPostProcessor.class,</span><br><span class="line">         WebServerFactoryCustomizerBeanPostProcessor::<span class="keyword">new</span>);</span><br><span class="line">   registerSyntheticBeanIfMissing(registry, <span class="string">&quot;errorPageRegistrarBeanPostProcessor&quot;</span>,</span><br><span class="line">         ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::<span class="keyword">new</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h3 id="ServletWebServerFactoryConfiguration"><a href="#ServletWebServerFactoryConfiguration" class="headerlink" title="ServletWebServerFactoryConfiguration"></a>ServletWebServerFactoryConfiguration</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> org.springframework.boot.autoconfigure.web.servlet;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ServletWebServerFactoryConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line">   <span class="meta">@ConditionalOnClass(&#123; Servlet.class, Tomcat.class, UpgradeProtocol.class &#125;)</span></span><br><span class="line">   <span class="meta">@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)</span></span><br><span class="line">   <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">EmbeddedTomcat</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="meta">@Bean</span></span><br><span class="line">      <span class="function">TomcatServletWebServerFactory <span class="title">tomcatServletWebServerFactory</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">            ObjectProvider&lt;TomcatConnectorCustomizer&gt; connectorCustomizers,</span></span></span><br><span class="line"><span class="function"><span class="params">            ObjectProvider&lt;TomcatContextCustomizer&gt; contextCustomizers,</span></span></span><br><span class="line"><span class="function"><span class="params">            ObjectProvider&lt;TomcatProtocolHandlerCustomizer&lt;?&gt;&gt; protocolHandlerCustomizers)</span> </span>&#123;</span><br><span class="line">         TomcatServletWebServerFactory factory = <span class="keyword">new</span> TomcatServletWebServerFactory();</span><br><span class="line">         factory.getTomcatConnectorCustomizers()</span><br><span class="line">               .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));</span><br><span class="line">         factory.getTomcatContextCustomizers()</span><br><span class="line">               .addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));</span><br><span class="line">         factory.getTomcatProtocolHandlerCustomizers()</span><br><span class="line">               .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));</span><br><span class="line">         <span class="keyword">return</span> factory;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * Nested configuration if Jetty is being used.</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   <span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line">   <span class="meta">@ConditionalOnClass(&#123; Servlet.class, Server.class, Loader.class, WebAppContext.class &#125;)</span></span><br><span class="line">   <span class="meta">@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)</span></span><br><span class="line">   <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">EmbeddedJetty</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="meta">@Bean</span></span><br><span class="line">      <span class="function">JettyServletWebServerFactory <span class="title">JettyServletWebServerFactory</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">            ObjectProvider&lt;JettyServerCustomizer&gt; serverCustomizers)</span> </span>&#123;</span><br><span class="line">         JettyServletWebServerFactory factory = <span class="keyword">new</span> JettyServletWebServerFactory();</span><br><span class="line">         factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));</span><br><span class="line">         <span class="keyword">return</span> factory;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * Nested configuration if Undertow is being used.</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   <span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line">   <span class="meta">@ConditionalOnClass(&#123; Servlet.class, Undertow.class, SslClientAuthMode.class &#125;)</span></span><br><span class="line">   <span class="meta">@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)</span></span><br><span class="line">   <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">EmbeddedUndertow</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="meta">@Bean</span></span><br><span class="line">      <span class="function">UndertowServletWebServerFactory <span class="title">undertowServletWebServerFactory</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">            ObjectProvider&lt;UndertowDeploymentInfoCustomizer&gt; deploymentInfoCustomizers,</span></span></span><br><span class="line"><span class="function"><span class="params">            ObjectProvider&lt;UndertowBuilderCustomizer&gt; builderCustomizers)</span> </span>&#123;</span><br><span class="line">         UndertowServletWebServerFactory factory = <span class="keyword">new</span> UndertowServletWebServerFactory();</span><br><span class="line">         factory.getDeploymentInfoCustomizers()</span><br><span class="line">               .addAll(deploymentInfoCustomizers.orderedStream().collect(Collectors.toList()));</span><br><span class="line">         factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().collect(Collectors.toList()));</span><br><span class="line">         <span class="keyword">return</span> factory;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="meta">@Bean</span></span><br><span class="line">      <span class="function">UndertowServletWebServerFactoryCustomizer <span class="title">undertowServletWebServerFactoryCustomizer</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">            ServerProperties serverProperties)</span> </span>&#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="keyword">new</span> UndertowServletWebServerFactoryCustomizer(serverProperties);</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>ServletWebServerFactory：服务器工厂，我们可以自己放Serlvet容器，我们自己放了就会用我们自己的</p>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022230030459.png" />

<p>XXXProvider的意思就是这些方法的参数都是从容器中拿，如果你自定义了，就用自定义的</p>
<h3 id="TomcatServletWebServerFactory自己new-Tomcat"><a href="#TomcatServletWebServerFactory自己new-Tomcat" class="headerlink" title="TomcatServletWebServerFactory自己new Tomcat()"></a>TomcatServletWebServerFactory自己new Tomcat()</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> WebServer <span class="title">getWebServer</span><span class="params">(ServletContextInitializer... initializers)</span> </span>&#123;</span><br><span class="line">   <span class="keyword">if</span> (<span class="keyword">this</span>.disableMBeanRegistry) &#123;</span><br><span class="line">      Registry.disableRegistry();</span><br><span class="line">   &#125;</span><br><span class="line">   Tomcat tomcat = <span class="keyword">new</span> Tomcat();</span><br><span class="line">   File baseDir = (<span class="keyword">this</span>.baseDirectory != <span class="keyword">null</span>) ? <span class="keyword">this</span>.baseDirectory : createTempDir(<span class="string">&quot;tomcat&quot;</span>);</span><br><span class="line">   tomcat.setBaseDir(baseDir.getAbsolutePath());</span><br><span class="line">   Connector connector = <span class="keyword">new</span> Connector(<span class="keyword">this</span>.protocol);</span><br><span class="line">   connector.setThrowOnFailure(<span class="keyword">true</span>);</span><br><span class="line">   tomcat.getService().addConnector(connector);</span><br><span class="line">   customizeConnector(connector);</span><br><span class="line">   tomcat.setConnector(connector);</span><br><span class="line">   tomcat.getHost().setAutoDeploy(<span class="keyword">false</span>);</span><br><span class="line">   configureEngine(tomcat.getEngine());</span><br><span class="line">   <span class="keyword">for</span> (Connector additionalConnector : <span class="keyword">this</span>.additionalTomcatConnectors) &#123;</span><br><span class="line">      tomcat.getService().addConnector(additionalConnector);</span><br><span class="line">   &#125;</span><br><span class="line">   prepareContext(tomcat.getHost(), initializers);</span><br><span class="line">   <span class="keyword">return</span> getTomcatWebServer(tomcat);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="Debug调用栈"><a href="#Debug调用栈" class="headerlink" title="Debug调用栈"></a>Debug调用栈</h4><img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022230533248.png" />



<h4 id="ServletWebServerApplicationContext"><a href="#ServletWebServerApplicationContext" class="headerlink" title="ServletWebServerApplicationContext"></a>ServletWebServerApplicationContext</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onRefresh</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">super</span>.onRefresh();</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">         createWebServer();</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">         <span class="keyword">throw</span> <span class="keyword">new</span> ApplicationContextException(<span class="string">&quot;Unable to start web server&quot;</span>, ex);</span><br><span class="line">      &#125;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">createWebServer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">	WebServer webServer = <span class="keyword">this</span>.webServer;</span><br><span class="line">	ServletContext servletContext = getServletContext();</span><br><span class="line">	<span class="keyword">if</span> (webServer == <span class="keyword">null</span> &amp;&amp; servletContext == <span class="keyword">null</span>) &#123;</span><br><span class="line">		StartupStep createWebServer = <span class="keyword">this</span>.getApplicationStartup().start(<span class="string">&quot;spring.boot.webserver.create&quot;</span>);</span><br><span class="line">		ServletWebServerFactory factory = getWebServerFactory();</span><br><span class="line">		createWebServer.tag(<span class="string">&quot;factory&quot;</span>, factory.getClass().toString());</span><br><span class="line">            <span class="comment">//最终在这里调用了TomcatServletWebServerFactory#getWebServer()</span></span><br><span class="line">		<span class="keyword">this</span>.webServer = factory.getWebServer(getSelfInitializer());</span><br><span class="line">		createWebServer.end();</span><br><span class="line">		getBeanFactory().registerSingleton(<span class="string">&quot;webServerGracefulShutdown&quot;</span>,</span><br><span class="line">				<span class="keyword">new</span> WebServerGracefulShutdownLifecycle(<span class="keyword">this</span>.webServer));</span><br><span class="line">		getBeanFactory().registerSingleton(<span class="string">&quot;webServerStartStop&quot;</span>,</span><br><span class="line">				<span class="keyword">new</span> WebServerStartStopLifecycle(<span class="keyword">this</span>, <span class="keyword">this</span>.webServer));</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span> (servletContext != <span class="keyword">null</span>) &#123;</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			getSelfInitializer().onStartup(servletContext);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">catch</span> (ServletException ex) &#123;</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> ApplicationContextException(<span class="string">&quot;Cannot initialize servlet context&quot;</span>, ex);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	initPropertySources();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>







<h4 id="返回到getWebServer并且调用prepareContext"><a href="#返回到getWebServer并且调用prepareContext" class="headerlink" title="返回到getWebServer并且调用prepareContext()"></a>返回到getWebServer并且调用prepareContext()</h4><img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022231006207.png"  />



<p>注意看<code>ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);</code>这一步就是Tomcat启动加载DispatcherServlet的时机</p>
<h2 id="Tomcat启动加载DispatcherServlet的时机"><a href="#Tomcat启动加载DispatcherServlet的时机" class="headerlink" title="Tomcat启动加载DispatcherServlet的时机"></a>Tomcat启动加载DispatcherServlet的时机</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> org.springframework.boot.autoconfigure.web.servlet;</span><br><span class="line"></span><br><span class="line"><span class="meta">@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)</span></span><br><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="meta">@ConditionalOnWebApplication(type = Type.SERVLET)</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(DispatcherServlet.class)</span></span><br><span class="line"><span class="meta">@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DispatcherServletAutoConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * The bean name for a DispatcherServlet that will be mapped to the root URL &quot;/&quot;.</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = <span class="string">&quot;dispatcherServlet&quot;</span>;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * The bean name for a ServletRegistrationBean for the DispatcherServlet &quot;/&quot;.</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = <span class="string">&quot;dispatcherServletRegistration&quot;</span>;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line">   <span class="meta">@Conditional(DefaultDispatcherServletCondition.class)</span></span><br><span class="line">   <span class="meta">@ConditionalOnClass(ServletRegistration.class)</span></span><br><span class="line">   <span class="meta">@EnableConfigurationProperties(WebMvcProperties.class)</span></span><br><span class="line">   <span class="keyword">protected</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DispatcherServletConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="meta">@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)</span></span><br><span class="line">      <span class="function"><span class="keyword">public</span> DispatcherServlet <span class="title">dispatcherServlet</span><span class="params">(WebMvcProperties webMvcProperties)</span> </span>&#123;</span><br><span class="line">         DispatcherServlet dispatcherServlet = <span class="keyword">new</span> DispatcherServlet();</span><br><span class="line">         dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());</span><br><span class="line">         dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());</span><br><span class="line">         dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());</span><br><span class="line">         dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());</span><br><span class="line">         dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());</span><br><span class="line">         <span class="keyword">return</span> dispatcherServlet;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="meta">@Bean</span></span><br><span class="line">      <span class="meta">@ConditionalOnBean(MultipartResolver.class)</span></span><br><span class="line">      <span class="meta">@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)</span></span><br><span class="line">      <span class="function"><span class="keyword">public</span> MultipartResolver <span class="title">multipartResolver</span><span class="params">(MultipartResolver resolver)</span> </span>&#123;</span><br><span class="line">         <span class="comment">// Detect if the user has created a MultipartResolver but named it incorrectly</span></span><br><span class="line">         <span class="keyword">return</span> resolver;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line">   <span class="meta">@Conditional(DispatcherServletRegistrationCondition.class)</span></span><br><span class="line">   <span class="meta">@ConditionalOnClass(ServletRegistration.class)</span></span><br><span class="line">   <span class="meta">@EnableConfigurationProperties(WebMvcProperties.class)</span></span><br><span class="line">   <span class="meta">@Import(DispatcherServletConfiguration.class)</span></span><br><span class="line">   <span class="keyword">protected</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DispatcherServletRegistrationConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="meta">@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)</span></span><br><span class="line">      <span class="meta">@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)</span></span><br><span class="line">      <span class="comment">//注意看DispatcherServletRegistrationBean</span></span><br><span class="line">      <span class="function"><span class="keyword">public</span> DispatcherServletRegistrationBean <span class="title">dispatcherServletRegistration</span><span class="params">(DispatcherServlet dispatcherServlet,</span></span></span><br><span class="line"><span class="function"><span class="params">            WebMvcProperties webMvcProperties, ObjectProvider&lt;MultipartConfigElement&gt; multipartConfig)</span> </span>&#123;</span><br><span class="line">         DispatcherServletRegistrationBean registration = <span class="keyword">new</span> DispatcherServletRegistrationBean(dispatcherServlet,</span><br><span class="line">               webMvcProperties.getServlet().getPath());</span><br><span class="line">         registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);</span><br><span class="line">         registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());</span><br><span class="line">         multipartConfig.ifAvailable(registration::setMultipartConfig);</span><br><span class="line">         <span class="keyword">return</span> registration;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// ......</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="DispatcherServletRegistrationBean继承树"><a href="#DispatcherServletRegistrationBean继承树" class="headerlink" title="DispatcherServletRegistrationBean继承树"></a>DispatcherServletRegistrationBean继承树</h3><p>我们发现DispatcherServletRegistrationBean它是一个ServletContextInitializer</p>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022231624162.png"/>



<p>F7进入上面说的这个<code>configureContext(context, initializersToUse);</code></p>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022231006207.png"  />







<h3 id="TomcatServletWebServerFactory-configureContext"><a href="#TomcatServletWebServerFactory-configureContext" class="headerlink" title="TomcatServletWebServerFactory#configureContext()"></a>TomcatServletWebServerFactory#configureContext()</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configureContext</span><span class="params">(Context context, ServletContextInitializer[] initializers)</span> </span>&#123;</span><br><span class="line">   TomcatStarter starter = <span class="keyword">new</span> TomcatStarter(initializers);<span class="comment">//注意在这里把这些ServletContextInitializer给了TomcatStarter</span></span><br><span class="line">   <span class="comment">// ......</span></span><br><span class="line">   <span class="keyword">for</span> (TomcatContextCustomizer customizer : <span class="keyword">this</span>.tomcatContextCustomizers) &#123;</span><br><span class="line">      customizer.customize(context);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="返回到TomcatServletWebServerFactory-getWebServer"><a href="#返回到TomcatServletWebServerFactory-getWebServer" class="headerlink" title="返回到TomcatServletWebServerFactory#getWebServer()"></a>返回到TomcatServletWebServerFactory#getWebServer()</h3><p>然后返回到getWebServer调用最后一步</p>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022232804479.png" />





<h3 id="TomcatStarter-onStartup"><a href="#TomcatStarter-onStartup" class="headerlink" title="TomcatStarter#onStartup()"></a>TomcatStarter#onStartup()</h3><p>最终初始化会调用到onStartup()</p>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022232711196.png"  />

<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">TomcatStarter(ServletContextInitializer[] initializers) &#123;</span><br><span class="line">   <span class="keyword">this</span>.initializers = initializers;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onStartup</span><span class="params">(Set&lt;Class&lt;?&gt;&gt; classes, ServletContext servletContext)</span> <span class="keyword">throws</span> ServletException </span>&#123;</span><br><span class="line">   <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">for</span> (ServletContextInitializer initializer : <span class="keyword">this</span>.initializers) &#123;</span><br><span class="line">         initializer.onStartup(servletContext);</span><br><span class="line">      &#125;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line">      <span class="keyword">this</span>.startUpException = ex;</span><br><span class="line">      <span class="comment">// Prevent Tomcat from logging and re-throwing when we know we can</span></span><br><span class="line">      <span class="comment">// deal with it in the main thread, but log for information here.</span></span><br><span class="line">      <span class="keyword">if</span> (logger.isErrorEnabled()) &#123;</span><br><span class="line">         logger.error(<span class="string">&quot;Error starting Tomcat context. Exception: &quot;</span> + ex.getClass().getName() + <span class="string">&quot;. Message: &quot;</span></span><br><span class="line">               + ex.getMessage());</span><br><span class="line">      &#125;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022232431746.png" />

<h3 id="RegistrationBean-onStartup"><a href="#RegistrationBean-onStartup" class="headerlink" title="RegistrationBean#onStartup()"></a>RegistrationBean#onStartup()</h3><img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022233001647.png" />

<p>F7进入，省略到一些不重要的方法</p>
<h3 id="DynamicRegistrationBean-register"><a href="#DynamicRegistrationBean-register" class="headerlink" title="DynamicRegistrationBean#register()"></a>DynamicRegistrationBean#register()</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">register</span><span class="params">(String description, ServletContext servletContext)</span> </span>&#123;</span><br><span class="line">   D registration = addRegistration(description, servletContext);</span><br><span class="line">   <span class="keyword">if</span> (registration == <span class="keyword">null</span>) &#123;</span><br><span class="line">      logger.info(StringUtils.capitalize(description) + <span class="string">&quot; was not registered (possibly already registered?)&quot;</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">   &#125;</span><br><span class="line">   configure(registration);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="ServletRegistration-Dynamic-addRegistration-将dispatcherServlet放入Tomcat容器中"><a href="#ServletRegistration-Dynamic-addRegistration-将dispatcherServlet放入Tomcat容器中" class="headerlink" title="ServletRegistration.Dynamic#addRegistration()将dispatcherServlet放入Tomcat容器中"></a>ServletRegistration.Dynamic#addRegistration()将dispatcherServlet放入Tomcat容器中</h3><img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022234633327.png" />

<p>servletContext这个就是tomcat容器</p>
<ol>
<li><p>ServletRegistration.Dynamic#addRegistration()将dispatcherServlet放入tomcat容器中</p>
</li>
<li><p>然后Tomcat启动之后自然就调用Servelt初始化，进而调到了dispatcherServlet，然后就是之前讲过的初始化web容器。</p>
<p><code>this.webApplicationContext = initWebApplicationContext();</code></p>
</li>
</ol>
<p>得到下面的结论</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringbootSourceApplication</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(SpringbootSourceApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span>  <span class="comment">//所有的xxxRegistrationBean都是允许我们注册原生的Servlet组件进去，</span></span><br><span class="line">    <span class="comment">//利用 ServletContextInitializer在Tomcat启动完成以后进行回调的机制</span></span><br><span class="line">    <span class="function">ServletRegistrationBean&lt;HelloServlet&gt; <span class="title">registrationBean</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">        ServletRegistrationBean&lt;HelloServlet&gt; registrationBean = <span class="keyword">new</span> ServletRegistrationBean&lt;&gt;(<span class="keyword">new</span> HelloServlet());</span><br><span class="line">        registrationBean.addUrlMappings(<span class="string">&quot;/he66&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> registrationBean;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="SpringApplication的run方法"><a href="#SpringApplication的run方法" class="headerlink" title="SpringApplication的run方法"></a>SpringApplication的run方法</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> ConfigurableApplicationContext <span class="title">run</span><span class="params">(String... args)</span> </span>&#123;</span><br><span class="line">   StopWatch stopWatch = <span class="keyword">new</span> StopWatch();</span><br><span class="line">   stopWatch.start();</span><br><span class="line">   DefaultBootstrapContext bootstrapContext = createBootstrapContext();</span><br><span class="line">   ConfigurableApplicationContext context = <span class="keyword">null</span>;</span><br><span class="line">   configureHeadlessProperty();</span><br><span class="line">   SpringApplicationRunListeners listeners = getRunListeners(args);</span><br><span class="line">   listeners.starting(bootstrapContext, <span class="keyword">this</span>.mainApplicationClass);</span><br><span class="line">   <span class="keyword">try</span> &#123;</span><br><span class="line">      ApplicationArguments applicationArguments = <span class="keyword">new</span> DefaultApplicationArguments(args);</span><br><span class="line">      ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);</span><br><span class="line">      configureIgnoreBeanInfo(environment);</span><br><span class="line">      Banner printedBanner = printBanner(environment);</span><br><span class="line">      <span class="comment">//创建容器</span></span><br><span class="line">      context = createApplicationContext();</span><br><span class="line">      context.setApplicationStartup(<span class="keyword">this</span>.applicationStartup);</span><br><span class="line">      prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);</span><br><span class="line">      <span class="comment">//刷新容器</span></span><br><span class="line">      refreshContext(context);</span><br><span class="line">      afterRefresh(context, applicationArguments);</span><br><span class="line">      stopWatch.stop();</span><br><span class="line">      <span class="keyword">if</span> (<span class="keyword">this</span>.logStartupInfo) &#123;</span><br><span class="line">         <span class="keyword">new</span> StartupInfoLogger(<span class="keyword">this</span>.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);</span><br><span class="line">      &#125;</span><br><span class="line">      listeners.started(context);</span><br><span class="line">      callRunners(context, applicationArguments);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">      handleRunFailure(context, ex, listeners);</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(ex);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">try</span> &#123;</span><br><span class="line">      listeners.running(context);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">      handleRunFailure(context, ex, <span class="keyword">null</span>);</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(ex);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">return</span> context;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>就是这样很简单</p>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.6/spring-sourcecode-v1/chapter_12/image-20211022235629787.png" />











</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">youthlql</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://imlql.cn/post/e3da4d66.html">https://imlql.cn/post/e3da4d66.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://imlql.cn" target="_blank">风祈的时光录</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/Spring%E6%BA%90%E7%A0%81/">Spring源码</a></div><div class="post_share"></div></div><div class="post-reward"><div class="reward-button"><i class="fas fa-qrcode"></i> 打赏</div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="https://npm.elemecdn.com/youthlql@1.0.8/blog/wechat.jpg" target="_blank"><img class="post-qr-code-img" src= "" data-lazy-src="https://npm.elemecdn.com/youthlql@1.0.8/blog/wechat.jpg" alt="微信"/></a><div class="post-qr-code-desc">微信</div></li><li class="reward-item"><a href="https://npm.elemecdn.com/youthlql@1.0.8/blog/alipay.jpg" target="_blank"><img class="post-qr-code-img" src= "" data-lazy-src="https://npm.elemecdn.com/youthlql@1.0.8/blog/alipay.jpg" alt="支付宝"/></a><div class="post-qr-code-desc">支付宝</div></li></ul></div></div><nav class="pagination-post" id="pagination"><div class="next-post pull-full"><a href="/post/4dfb096b.html"><img class="next-cover" src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/logo/spring.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Spring源码系列-第11章-SpringMVC异常处理源码和@EnableWebMvc原理</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/post/41fb8d9e.html" title="Spring源码系列-第2章-后置工厂处理器和Bean生命周期"><img class="cover" src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/logo/spring.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-12-21</div><div class="title">Spring源码系列-第2章-后置工厂处理器和Bean生命周期</div></div></a></div><div><a href="/post/49f419ae.html" title="Spring源码系列-第4章-Bean初始化流程"><img class="cover" src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/logo/spring.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-01-27</div><div class="title">Spring源码系列-第4章-Bean初始化流程</div></div></a></div><div><a href="/post/fb3552e0.html" title="Spring源码系列-第7章-AOP的执行流程原理和监听器原理"><img class="cover" src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/logo/spring.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-04-17</div><div class="title">Spring源码系列-第7章-AOP的执行流程原理和监听器原理</div></div></a></div><div><a href="/post/c8dd1418.html" title="Spring源码系列-第8章-SpringMVC子容器和Spring父容器的启动原理"><img class="cover" src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/logo/spring.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-06-20</div><div class="title">Spring源码系列-第8章-SpringMVC子容器和Spring父容器的启动原理</div></div></a></div><div><a href="/post/6f2cef28.html" title="Spring源码系列-第9章-SpringMVC请求处理源码和HandlerMapping原理"><img class="cover" src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/logo/spring.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-06-21</div><div class="title">Spring源码系列-第9章-SpringMVC请求处理源码和HandlerMapping原理</div></div></a></div><div><a href="/post/4dfb096b.html" title="Spring源码系列-第11章-SpringMVC异常处理源码和@EnableWebMvc原理"><img class="cover" src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/logo/spring.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-01-05</div><div class="title">Spring源码系列-第11章-SpringMVC异常处理源码和@EnableWebMvc原理</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content is-expand"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E7%AC%AC12%E7%AB%A0-SpringBoot%E6%BA%90%E7%A0%81-%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86%E5%92%8C%E5%86%85%E5%B5%8CTomcat%E5%90%AF%E5%8A%A8%E5%8E%9F%E7%90%86"><span class="toc-text">第12章-SpringBoot源码-自动配置原理和内嵌Tomcat启动原理</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B5%8C%E5%85%A5%E5%BC%8FTomcat%E4%B8%8ESpring%E6%95%B4%E5%90%88"><span class="toc-text">嵌入式Tomcat与Spring整合</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B5%8B%E8%AF%95%E7%B1%BB"><span class="toc-text">测试类</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%B5%8B%E8%AF%95%E9%A1%B9%E7%9B%AE%E7%9B%AE%E5%BD%95"><span class="toc-text">测试项目目录</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#pom-xml"><span class="toc-text">pom.xml</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Main"><span class="toc-text">Main</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#QuickAppStarter"><span class="toc-text">QuickAppStarter</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#SpringConfig"><span class="toc-text">SpringConfig</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#SpringMVCConfig"><span class="toc-text">SpringMVCConfig</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#HelloController"><span class="toc-text">HelloController</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B5%8B%E8%AF%95%E6%95%88%E6%9E%9C"><span class="toc-text">测试效果</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%86%8D%E6%9D%A5%E7%AE%80%E5%8D%95%E6%8D%8B%E4%B8%80%E4%B8%8BSPI%E5%A6%82%E4%BD%95%E5%90%AF%E5%8A%A8%E7%9A%84Web%E5%AE%B9%E5%99%A8"><span class="toc-text">再来简单捋一下SPI如何启动的Web容器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#META-INF-services"><span class="toc-text">META-INF&#x2F;services</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#AbstractAnnotationConfigDispatcherServletInitializer%E7%BB%A7%E6%89%BF%E6%A0%91"><span class="toc-text">AbstractAnnotationConfigDispatcherServletInitializer继承树</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SpringServletContainerInitializer"><span class="toc-text">SpringServletContainerInitializer</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#HandlesTypes"><span class="toc-text">@HandlesTypes</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Servlet%E7%9B%B8%E5%85%B3%E8%A7%84%E8%8C%83"><span class="toc-text">Servlet相关规范</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#DispatcherServlet"><span class="toc-text">DispatcherServlet</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#FrameworkServlet"><span class="toc-text">FrameworkServlet</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#SpringBoot%E5%90%AF%E5%8A%A8%E5%AF%BC%E5%85%A5%E4%BA%86%E5%BE%88%E5%A4%9A%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%B1%BB"><span class="toc-text">SpringBoot启动导入了很多自动配置类</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#pom-xml-1"><span class="toc-text">pom.xml</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SpringBootApplication%E5%8E%9F%E7%90%86"><span class="toc-text">@SpringBootApplication原理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SpringBootConfiguration"><span class="toc-text">@SpringBootConfiguration</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#EnableAutoConfiguration"><span class="toc-text">@EnableAutoConfiguration</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#AutoConfigurationPackage"><span class="toc-text">@AutoConfigurationPackage</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#AutoConfigurationPackage%E5%AF%BC%E5%85%A5%E7%9A%84AutoConfigurationPackages-Registrar%E7%B1%BB"><span class="toc-text">@AutoConfigurationPackage导入的AutoConfigurationPackages.Registrar类</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#AutoConfigurationPackages-Registrar-registerBeanDefinitions"><span class="toc-text">AutoConfigurationPackages.Registrar#registerBeanDefinitions()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#AutoConfigurationPackages-register"><span class="toc-text">AutoConfigurationPackages#register()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#AutoConfigurationPackages-BasePackagesBeanDefinition"><span class="toc-text">AutoConfigurationPackages.BasePackagesBeanDefinition</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#BeanDefinitionMap%E9%87%8C%E7%9A%84%E6%95%B0%E6%8D%AE"><span class="toc-text">BeanDefinitionMap里的数据</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#EnableAutoConfiguration%E6%B3%A8%E8%A7%A3%E5%AF%BC%E5%85%A5%E7%9A%84AutoConfigurationImportSelector%E7%B1%BB"><span class="toc-text">@EnableAutoConfiguration注解导入的AutoConfigurationImportSelector类</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#AutoConfigurationImportSelector-AutoConfigurationGroup-process"><span class="toc-text">AutoConfigurationImportSelector.AutoConfigurationGroup#process()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#AutoConfigurationImportSelector-getAutoConfigurationEntry"><span class="toc-text">AutoConfigurationImportSelector#getAutoConfigurationEntry()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#AutoConfigurationImportSelector-getCandidateConfigurations"><span class="toc-text">AutoConfigurationImportSelector#getCandidateConfigurations()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SpringFactoriesLoader-loadFactoryNames"><span class="toc-text">SpringFactoriesLoader#loadFactoryNames()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SpringFactoriesLoader-loadSpringFactories-%E5%8A%A0%E8%BD%BD%E7%B1%BB%E8%B7%AF%E5%BE%84%E4%B8%8BMETA-INF-spring-factories%E7%9A%84%E8%B5%84%E6%BA%90"><span class="toc-text">SpringFactoriesLoader#loadSpringFactories()加载类路径下META-INF&#x2F;spring.factories的资源</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#spring-factories"><span class="toc-text">spring.factories</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%BF%94%E5%9B%9E%E5%88%B0AutoConfigurationImportSelector-getAutoConfigurationEntry"><span class="toc-text">返回到AutoConfigurationImportSelector#getAutoConfigurationEntry()</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AE%B9%E5%99%A8%E5%88%B7%E6%96%B0%E5%9C%A8onRefresh%E6%AD%A5%E9%AA%A4%E4%BC%9A%E5%90%AF%E5%8A%A8Tomcat"><span class="toc-text">容器刷新在onRefresh步骤会启动Tomcat</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#DispatcherServletAutoConfiguration"><span class="toc-text">DispatcherServletAutoConfiguration</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#ServletWebServerFactoryAutoConfiguration"><span class="toc-text">ServletWebServerFactoryAutoConfiguration</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#ServletWebServerFactoryAutoConfiguration-BeanPostProcessorsRegistrar"><span class="toc-text">ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#ServletWebServerFactoryConfiguration"><span class="toc-text">ServletWebServerFactoryConfiguration</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#TomcatServletWebServerFactory%E8%87%AA%E5%B7%B1new-Tomcat"><span class="toc-text">TomcatServletWebServerFactory自己new Tomcat()</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Debug%E8%B0%83%E7%94%A8%E6%A0%88"><span class="toc-text">Debug调用栈</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ServletWebServerApplicationContext"><span class="toc-text">ServletWebServerApplicationContext</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%BF%94%E5%9B%9E%E5%88%B0getWebServer%E5%B9%B6%E4%B8%94%E8%B0%83%E7%94%A8prepareContext"><span class="toc-text">返回到getWebServer并且调用prepareContext()</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Tomcat%E5%90%AF%E5%8A%A8%E5%8A%A0%E8%BD%BDDispatcherServlet%E7%9A%84%E6%97%B6%E6%9C%BA"><span class="toc-text">Tomcat启动加载DispatcherServlet的时机</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#DispatcherServletRegistrationBean%E7%BB%A7%E6%89%BF%E6%A0%91"><span class="toc-text">DispatcherServletRegistrationBean继承树</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#TomcatServletWebServerFactory-configureContext"><span class="toc-text">TomcatServletWebServerFactory#configureContext()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%BF%94%E5%9B%9E%E5%88%B0TomcatServletWebServerFactory-getWebServer"><span class="toc-text">返回到TomcatServletWebServerFactory#getWebServer()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#TomcatStarter-onStartup"><span class="toc-text">TomcatStarter#onStartup()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#RegistrationBean-onStartup"><span class="toc-text">RegistrationBean#onStartup()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#DynamicRegistrationBean-register"><span class="toc-text">DynamicRegistrationBean#register()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#ServletRegistration-Dynamic-addRegistration-%E5%B0%86dispatcherServlet%E6%94%BE%E5%85%A5Tomcat%E5%AE%B9%E5%99%A8%E4%B8%AD"><span class="toc-text">ServletRegistration.Dynamic#addRegistration()将dispatcherServlet放入Tomcat容器中</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#SpringApplication%E7%9A%84run%E6%96%B9%E6%B3%95"><span class="toc-text">SpringApplication的run方法</span></a></li></ol></li></ol></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2023 By youthlql</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text"><a href="https://www.upyun.com/?utm_source=lianmeng&utm_medium=referral" target="_blank" rel="noopener" class="one-pan-link-mark"><img style="position:relative;top:-3px; " src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/upyun/logo.png" align="absmiddle" width="60px" height="30px"></a><a target="_blank" rel="noopener" href="https://beian.miit.gov.cn"><img class="icp-icon" src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/logo/icp.png"><span>鄂ICP备19028890号</span></a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="translateLink" type="button" title="简繁转换">简</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">本地搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/tw_cn.js"></script><script src="https://npm.elemecdn.com/@fancyapps/ui/dist/fancybox.umd.js"></script><script src="https://npm.elemecdn.com/instant.page/instantpage.js" type="module"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><script src="/js/search/local-search.js"></script><div class="js-pjax"></div><script defer src="https://npm.elemecdn.com/jquery@latest/dist/jquery.min.js"></script></div></body></html>